#include "Framework.h"

#pragma once
#include <stdio.h>
#pragma comment(lib, "winmm.lib")

#define PI 3.14159265358979323846

Framework::Framework()
{
	//Framework
	m_bVsync		= false;
	m_pD3DObject	= 0;
	m_pD3DDevice	= 0;

	selection = last_position = current_position = cursor_position = vec2(4,4);

	once = timeElapsed = 0;

	retval = 1;
}	

Framework::~Framework()
{
	Shutdown();
}

void Framework::Init(HWND& hWnd, HINSTANCE& hInst, bool bWindowed)
{
	m_hWnd = hWnd;

	//////////////////////////////////////////////////////////////////////////
	// Direct3D Foundations - D3D Object, Present Parameters, and D3D Device
	//////////////////////////////////////////////////////////////////////////

	// Create the D3D Object
	m_pD3DObject = Direct3DCreate9(D3D_SDK_VERSION);

	// Find the width and height of window using hWnd and GetWindowRect()
	RECT rect;
	GetWindowRect(hWnd, &rect);
	int width = rect.right - rect.left;	
	int height = rect.bottom - rect.top;

	// Set D3D Device presentation parameters before creating the device
	D3DPRESENT_PARAMETERS D3Dpp;
	ZeroMemory(&D3Dpp, sizeof(D3Dpp));  // NULL the structure's memory

	D3Dpp.hDeviceWindow					= hWnd;										// Handle to the focus window
	D3Dpp.Windowed						= bWindowed;								// Windowed or Full-screen boolean
	D3Dpp.AutoDepthStencilFormat		= D3DFMT_D24S8;								// Format of depth/stencil buffer, 24 bit depth, 8 bit stencil
	D3Dpp.EnableAutoDepthStencil		= TRUE;										// Enables Z-Buffer (Depth Buffer)
	D3Dpp.BackBufferCount				= 1;										// Change if need of > 1 is required at a later date
	D3Dpp.BackBufferFormat				= D3DFMT_X8R8G8B8;							// Back-buffer format, 8 bits for each pixel
	D3Dpp.BackBufferHeight				= height;									// Make sure resolution is supported, use adapter modes
	D3Dpp.BackBufferWidth				= width;									// (Same as above)
	D3Dpp.SwapEffect					= D3DSWAPEFFECT_DISCARD;					// Discard back-buffer, must stay discard to support multi-sample
	D3Dpp.PresentationInterval			= m_bVsync ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE; // Present back-buffer immediately, unless V-Sync is on								
	D3Dpp.Flags							= D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;		// This flag should improve performance, if not set to NULL.
	D3Dpp.FullScreen_RefreshRateInHz	= bWindowed ? 0 : D3DPRESENT_RATE_DEFAULT;	// Full-screen refresh rate, use adapter modes or default
	D3Dpp.MultiSampleQuality			= 0;										// MSAA currently off, check documentation for support.
	D3Dpp.MultiSampleType				= D3DMULTISAMPLE_NONE;						// MSAA currently off, check documentation for support.

	// Check device capabilities
	DWORD deviceBehaviorFlags = 0;
	m_pD3DObject->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &m_D3DCaps);

	// Determine vertex processing mode
	if(m_D3DCaps.DevCaps & D3DCREATE_HARDWARE_VERTEXPROCESSING)
	{
		// Hardware vertex processing supported? (Video Card)
		deviceBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;	
	}
	else
	{
		// If not, use software (CPU)
		deviceBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING; 
	}
	
	// If hardware vertex processing is on, check pure device support
	if(m_D3DCaps.DevCaps & D3DDEVCAPS_PUREDEVICE && deviceBehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING)
	{
		deviceBehaviorFlags |= D3DCREATE_PUREDEVICE;	
	}
	
	// Create the D3D Device with the present parameters and device flags above
	m_pD3DObject->CreateDevice(
		D3DADAPTER_DEFAULT,		// which adapter to use, set to primary
		D3DDEVTYPE_HAL,			// device type to use, set to hardware rasterization
		hWnd,					// handle to the focus window
		deviceBehaviorFlags,	// behavior flags
		&D3Dpp,					// presentation parameters
		&m_pD3DDevice);			// returned device pointer


	//////////////////////////////////////////////////////////////////////////
	// Direct Input
	//////////////////////////////////////////////////////////////////////////
	DirectInput8Create(hInst,					// the handle to the application
                       DIRECTINPUT_VERSION,		// the compatible version
                       IID_IDirectInput8,		// the DirectInput interface version
                       (void**)&m_pDirectInput, // the pointer to the interface
                       NULL);					// COM stuff, so we'll set it to NULL
	
	/*
    //Create the keyboard device
	m_pDirectInput->CreateDevice(GUID_SysKeyboard,    // the default keyboard ID being used
                      &m_pInKeyboard,    // the pointer to the device interface
                      NULL);    // COM stuff, so we'll set it to NULL

    //Set the data format to keyboard format
    m_pInKeyboard->SetDataFormat(&c_dfDIKeyboard);

	//Set the control you will have over the keyboard
    m_pInKeyboard->SetCooperativeLevel(hWnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);


	m_pDirectInput->CreateDevice(GUID_SysMouse,
                      &m_pInMouse,
                      NULL);

	m_pInMouse->SetDataFormat(&c_dfDIMouse);

	m_pInMouse->SetCooperativeLevel(hWnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND);

	m_pInMouse->Acquire();

	*/

	//////////////////////////////////////////////////////////////////////////
	// Create a Font Object
	//////////////////////////////////////////////////////////////////////////
	
	AddFontResourceEx(L"Delicious-Roman.otf", FR_PRIVATE, 0);

	D3DXCreateFont(m_pD3DDevice, 20, 0, FW_BOLD, 0, false, DEFAULT_CHARSET, 
		OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Calibri"), &m_pD3DFont);


	//////////////////////////////////////////////////////////////////////////
	// Create Sprite Object and Textures
	//////////////////////////////////////////////////////////////////////////

	//Note you will only need one sprite object for all 2D sprites
	D3DXCreateSprite(m_pD3DDevice, &m_pD3DSprite);



	D3DXCreateTextureFromFileEx(m_pD3DDevice, L"ship.png", 0, 0, 0, 0, 
		D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 
		D3DCOLOR_XRGB(255, 255, 255), &m_imageInfo, 0, &m_pTexture[0]);

	D3DXCreateTextureFromFileEx(m_pD3DDevice, L"block.png", 0, 0, 0, 0, 
		D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 
		D3DCOLOR_XRGB(255, 255, 255), &m_imageInfo, 0, &m_pTexture[1]);

	D3DXCreateTextureFromFileEx(m_pD3DDevice, L"cursor.png", 0, 0, 0, 0, 
		D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 
		D3DCOLOR_XRGB(255, 255, 255), &m_imageInfo, 0, &m_pTexture[2]);



	//////////////////////////////////////////////////////////////////////////
	// Initialize FMOD
	//////////////////////////////////////////////////////////////////////////

	//result = FMOD::System_Create(&system);		// Create the main system object.
	//if (result != FMOD_OK)
	//{
	//	//printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
	//	exit(-1);
	//}

	//result = system->init(100, FMOD_INIT_NORMAL, 0);	// Initialize FMOD.
	//if (result != FMOD_OK)
	//{
	//	//printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
	//	exit(-1);
	//}


	//system->createSound("example sound.wav", FMOD_DEFAULT, 0, &sound);
	//channel[0]->setVolume(0.6f);

	//system->createStream("example music.wav", FMOD_LOOP_NORMAL | FMOD_2D | FMOD_HARDWARE, 0, &stream);
	//channel[1]->setVolume(0.2f);
	//system->playSound(FMOD_CHANNEL_FREE, stream, false, &channel[1]);

	//Initialize quadrant
	int a(0),x(130),y(40);
	for(int i = 1; i <= 8; ++i) //Eight columns
	{
		for(int j = 1; j <= 8; ++j) //by eight rows
		{
			sector_area[a].x = x;
			sector_area[a].y = y;
			x += 65;
			a++;

		}
		y += 65;
	}

	//////////////////////////////////////////////////////////////////////////
	// Initialize WinSock
	//////////////////////////////////////////////////////////////////////////

	WSAStartup(MAKEWORD(2,0), &wsaData);

	RunClient();

}

void Framework::Update(float dt)
{
	m_pDt = dt;

	timeElapsed += (dt * 0.001f);

	GetCursorPos(&pt);
	ScreenToClient(m_hWnd, &pt);

	//Cursor position

	//X-axis
	if(pt.x > 50 && pt.x < 115)
		cursor_position.x = 1;
	else if(pt.x > 115 && pt.x < 180)
		cursor_position.x = 2;
	else if(pt.x > 180 && pt.x < 245)
		cursor_position.x = 3;
	else if(pt.x > 245 && pt.x < 310)
		cursor_position.x = 4;
	else if(pt.x > 310 && pt.x < 375)
		cursor_position.x = 5;
	else if(pt.x > 375 && pt.x < 440)
		cursor_position.x = 6;
	else if(pt.x > 440 && pt.x < 505)
		cursor_position.x = 7;
	else if(pt.x > 505 && pt.x < 570)
		cursor_position.x = 8;
	else
		cursor_position.x = 0;

	//Y-axis
	if(pt.y > 45 && pt.y < 100)
		cursor_position.y = 1;
	else if(pt.y > 100 && pt.y < 165)
		cursor_position.y = 2;
	else if(pt.y > 165 && pt.y < 230)
		cursor_position.y = 3;
	else if(pt.y > 230 && pt.y < 295)
		cursor_position.y = 4;
	else if(pt.y > 295 && pt.y < 360)
		cursor_position.y = 5;
	else if(pt.y > 360 && pt.y < 425)
		cursor_position.y = 6;
	else if(pt.y > 425 && pt.y < 490)
		cursor_position.y = 7;
	else if(pt.y > 490 && pt.y < 555)
		cursor_position.y = 8;
	else
		cursor_position.y = 0;
	
	//Handle mouse event
	if(click && cursor_position.x > 0 && cursor_position.x <= 8
			&& cursor_position.y > 0 && cursor_position.y <= 8)
	{
		timeElapsed = 0;
		last_position = selection;

		//X-axis
		if(pt.x > 50 && pt.x < 115)
			selection.x = 1;
		else if(pt.x > 115 && pt.x < 180)
			selection.x = 2;
		else if(pt.x > 180 && pt.x < 245)
			selection.x = 3;
		else if(pt.x > 245 && pt.x < 310)
			selection.x = 4;
		else if(pt.x > 310 && pt.x < 375)
			selection.x = 5;
		else if(pt.x > 375 && pt.x < 440)
			selection.x = 6;
		else if(pt.x > 440 && pt.x < 505)
			selection.x = 7;
		else if(pt.x > 505 && pt.x < 570)
			selection.x = 8;

		//Y-axis
		if(pt.y > 45 && pt.y < 100)
			selection.y = 1;
		else if(pt.y > 100 && pt.y < 165)
			selection.y = 2;
		else if(pt.y > 165 && pt.y < 230)
			selection.y = 3;
		else if(pt.y > 230 && pt.y < 295)
			selection.y = 4;
		else if(pt.y > 295 && pt.y < 360)
			selection.y = 5;
		else if(pt.y > 360 && pt.y < 425)
			selection.y = 6;
		else if(pt.y > 425 && pt.y < 490)
			selection.y = 7;
		else if(pt.y > 490 && pt.y < 555)
			selection.y = 8;

	}

	click = 0;

	
	if(timeElapsed >= 0.1f)
	{
		if(current_position.x != selection.x && delta_position.x >= delta_position.y)
			current_position.x = selection.x - current_position.x < 0 ? current_position.x - 1 : current_position.x + 1;

		if(current_position.y != selection.y && delta_position.y >= delta_position.x)
			current_position.y = selection.y - current_position.y < 0 ? current_position.y - 1 : current_position.y + 1;

		//Change in coordinates
		delta_position.x = selection.x - current_position.x >= 0 ? selection.x - current_position.x : (selection.x - current_position.x) * -1;
		delta_position.y = selection.y - current_position.y >= 0 ? selection.y - current_position.y : (selection.y - current_position.y) * -1;

		timeElapsed = 0;
	}

	/*if(!once)
	{
		if(GetAsyncKeyState(VK_LEFT) && selection.x > 1)
		{
			selection.x--;
			once = true;
		}

		if(GetAsyncKeyState(VK_RIGHT) && selection.x < 8)
		{
			selection.x++;
			once = true;
		}

		if(GetAsyncKeyState(VK_DOWN) && selection.y < 8)
		{
			selection.y++;
			once = true;
		}

		if(GetAsyncKeyState(VK_UP) && selection.y > 1)
		{
			selection.y--;
			once = true;
		}

	}

	if(!(GetAsyncKeyState(VK_LEFT) & 0x8000) &&
		!(GetAsyncKeyState(VK_RIGHT) & 0x8000) &&
		!(GetAsyncKeyState(VK_DOWN) & 0x8000) &&
		!(GetAsyncKeyState(VK_UP) & 0x8000))
		once = false;*/

	//Wait for data from server
	//retval = recv(Socket, buffer, sizeof(buffer)-1, 0);

	if(retval == 0)
	{
		closesocket(Socket);
		MessageBox(m_hWnd, L"Connection to server lost.", L"Disconnected", 0);
		PostQuitMessage(0);
	}
}

void Framework::Render()
{
	//Return if failed
	if(!m_pD3DDevice)
		return;


	if(SUCCEEDED(m_pD3DDevice->Clear(0, 0, D3DCLEAR_TARGET, D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f), 1.0f, 0)))
	{
		if(SUCCEEDED(m_pD3DDevice->BeginScene()))
		{
			if(SUCCEEDED(m_pD3DSprite->Begin(D3DXSPRITE_ALPHABLEND | D3DXSPRITE_SORT_DEPTH_FRONTTOBACK)))
			{
				D3DXMATRIX transMat, rotMat, scaleMat, worldMat;
				D3DXMatrixIdentity(&transMat);
				D3DXMatrixIdentity(&scaleMat);
				D3DXMatrixIdentity(&rotMat);
				D3DXMatrixIdentity(&worldMat);


				
				//Draw quadrant
				for(int i = 1; i <= 8; ++i) //Eight columns
				{
					for(int j = 1; j <= 8; ++j) //by eight rows
					{
						D3DXMatrixScaling(&scaleMat, 0.5f, 0.5f, 1.0f);
						D3DXMatrixTranslation(&transMat, j*65, i*65, 0.0f);
						D3DXMatrixRotationZ(&rotMat, D3DXToRadian(0.0f));
						D3DXMatrixMultiply(&worldMat, &scaleMat, &transMat);

						m_pD3DSprite->SetTransform(&worldMat);


						//m_pD3DSprite->Draw(m_pTexture[1], 0, &D3DXVECTOR3(m_imageInfo.Width * 0.5f, m_imageInfo.Height * 0.5f, 0.0f), //bg block
						//	0, D3DCOLOR_ARGB(255, 20, 20, 20));


						D3DXMatrixScaling(&scaleMat, 0.18f, 0.18f, 0.18f);
						D3DXMatrixTranslation(&transMat, j*64, i*64, 0.0f);
						D3DXMatrixRotationZ(&rotMat, D3DXToRadian(0.0f));
						D3DXMatrixMultiply(&worldMat, &scaleMat, &transMat);

						m_pD3DSprite->SetTransform(&worldMat);
				
						if(current_position.x == j && current_position.y == i)
						{
							m_pD3DSprite->Draw(m_pTexture[0], 0, &D3DXVECTOR3(m_imageInfo.Width * 0.5f, m_imageInfo.Height * 0.5f, 0.0f), //ship
									0, D3DCOLOR_ARGB(255, 255, 255, 255));
						}
						else if(last_position.x == j && last_position.y == i)
						{
							D3DXMatrixScaling(&scaleMat, 0.5f, 0.5f, 1.0f);
							D3DXMatrixTranslation(&transMat, j*65, i*65, 0.0f);
							D3DXMatrixRotationZ(&rotMat, D3DXToRadian(0.0f));
							D3DXMatrixMultiply(&worldMat, &scaleMat, &transMat);

							m_pD3DSprite->SetTransform(&worldMat);

							m_pD3DSprite->Draw(m_pTexture[1], 0, &D3DXVECTOR3(m_imageInfo.Width * 0.5f, m_imageInfo.Height * 0.5f, 0.0f), //last
									0, D3DCOLOR_ARGB(255, 255, 10, 10));
						}

						if(cursor_position.x == j && cursor_position.y == i)
						{
							D3DXMatrixScaling(&scaleMat, 0.7f, 0.7f, 1.0f);
							D3DXMatrixTranslation(&transMat, j*66.7, i*66.7, 0.0f);
							D3DXMatrixRotationZ(&rotMat, D3DXToRadian(timeGetTime()*0.1f));
							D3DXMatrixMultiply(&worldMat, &scaleMat, &transMat);
							D3DXMatrixMultiply(&worldMat, &rotMat, &worldMat);

							m_pD3DSprite->SetTransform(&worldMat);

							if(click)
							{
								m_pD3DSprite->Draw(m_pTexture[2], 0, &D3DXVECTOR3(m_imageInfo.Width * 0.5f, m_imageInfo.Height * 0.5f, 0.0f),
									0, D3DCOLOR_ARGB(255, 255, 255, 255));
							}
							else
							{
								m_pD3DSprite->Draw(m_pTexture[2], 0, &D3DXVECTOR3(65, 65, 0.0f), //cursor
										0, D3DCOLOR_ARGB(100, 255, 255, 255));
							}
						}

					}
				}
		
					
				
				m_pD3DSprite->End();
			}

			//Draw text
			wchar_t buffer[64];

			RECT rect;
			GetWindowRect(m_hWnd, &rect);
			rect.right = rect.right - rect.left;
			rect.bottom = rect.bottom - rect.top;
			rect.left = 5;
			rect.top = 30;

			swprintf_s(buffer, 64, L"DELTA X:%i", (int)delta_position.x);

			m_pD3DFont->DrawText(0, buffer, -1, &rect, DT_CENTER | DT_NOCLIP, D3DCOLOR_ARGB(255, 255,0,0));

			swprintf_s(buffer, 64, L"DELTA Y:%i", (int)delta_position.y);

			rect.left += 300;

			m_pD3DFont->DrawText(0, buffer, -1, &rect, DT_CENTER | DT_NOCLIP, D3DCOLOR_ARGB(255, 255,0,0));

			m_pD3DDevice->EndScene();
		}

		m_pD3DDevice->Present(0, 0, 0, 0);

	}
}

void Framework::RunClient()
{
	char		tempBuffer[128];
	sockaddr_in sockAddr = {0};
	bool		bSuccess = true;
	
	sockAddr.sin_family = AF_INET;
	sockAddr.sin_port = htons(4444);
	sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

	// Create socket
	Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	// Connect to server
	connect(Socket, reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockAddr));
}

void Framework::Shutdown()
{
	//Release COM objects in the opposite order they were created in
	for(int i = 0; i < 2; ++i)SAFE_RELEASE(m_pTexture[i]);
	SAFE_RELEASE(m_pD3DSprite);
	SAFE_RELEASE(m_pD3DFont);
	SAFE_RELEASE(m_pD3DDevice);
	SAFE_RELEASE(m_pD3DObject);
	//m_pInMouse->Unacquire();

	//Clean up WinSock
	WSACleanup();
}